package com.i360day.invoker;

import com.i360day.invoker.annotation.RemoteClientEntity;
import com.i360day.invoker.context.HttpInvokerContext;
import com.i360day.invoker.executor.HttpInvokerRequestExecutor;
import com.i360day.invoker.proxy.TargetProxy;
import com.i360day.invoker.proxy.Targeter;
import com.i360day.invoker.support.RemoteInvocationFactory;
import com.i360day.invoker.support.UrlBasedRemoteAccessor;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;

/**
 * @author liju.z
 */
@Order(Integer.MIN_VALUE)
public class HttpInvokerClientFactoryBean extends UrlBasedRemoteAccessor implements FactoryBean<Object>, ApplicationContextAware {

    private HttpInvokerContext httpInvokerContext;

    private TargetProxy targetProxy;

    private RemoteClientEntity remoteClient;

    public HttpInvokerClientFactoryBean(RemoteClientEntity remoteClient) {
        this.remoteClient = remoteClient;
    }

    @Override
    public void afterPropertiesSet() {
        super.afterPropertiesSet();

        if (getServiceInterface() == null) {
            throw new IllegalArgumentException("Property 'serviceInterface' is required");
        }

        if (this.remoteClient == null) {
            throw new IllegalArgumentException(String.format("proxy %s, There is no remoteClient parameter in the constructor ", getServiceInterface()));
        }

        //代理对象
        this.targetProxy = new TargetProxy(getServiceInterface(), remoteClient.getName(), getServiceUrl(), getBeanClassLoader());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //http invoker context
        this.httpInvokerContext = applicationContext.getBean(HttpInvokerContext.class);
    }

    @Override
    public Object getObject() {
        return new ProxyFactory(getServiceInterface(), getInvocationHandler()).getProxy(getBeanClassLoader());
    }

    @Override
    public Class<?> getObjectType() {
        return getServiceInterface();
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public String toString() {
        return getTargetProxy().toString();
    }

    @Override
    public int hashCode() {
        return getTargetProxy().hashCode();
    }

    public TargetProxy getTargetProxy() {
        return targetProxy;
    }

    /**
     * InvokerBuilder
     *
     * @return
     */
    private MethodInterceptor getInvocationHandler() {

        //创建代理请求执行器
        HttpInvokerClientMethodInterceptor httpInvokerClientMethodInterceptor = new HttpInvokerClientMethodInterceptor(
                targetProxy,
                httpInvokerContext.getBean(HttpInvokerRequestExecutor.class),
                httpInvokerContext.getBean(RemoteInvocationFactory.class)
        );
 
        //create proxy
        return InvokerBuilder.create()
                .name(remoteClient.getName())
                .address(remoteClient.getAddress())
                .contextPath(remoteClient.getContextPath())
                .targetProxy(getTargetProxy())
                .fallback(remoteClient.getFallback())
                .httpInvokerContext(httpInvokerContext)
                .fallbackFactory(remoteClient.getFallbackFactory())
                .interceptor(httpInvokerClientMethodInterceptor)
                .targeter(httpInvokerContext.getBean(Targeter.class))
                .build()
                ;
    }
}
